omyacid: Old Mouse Yells At Cloud-init Daemon
HTTP daemon that interfaces with nzrd to get cloud-init metadata to instances. The current iteration is completely untested.
This commit is contained in:
		
							parent
							
								
									51e72fed93
								
							
						
					
					
						commit
						e4df2e5075
					
				
					 8 changed files with 604 additions and 15 deletions
				
			
		
							
								
								
									
										347
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										347
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							|  | @ -108,6 +108,50 @@ version = "1.0.86" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "askama" | ||||
| version = "0.12.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" | ||||
| dependencies = [ | ||||
|  "askama_derive", | ||||
|  "askama_escape", | ||||
|  "humansize", | ||||
|  "num-traits", | ||||
|  "percent-encoding", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "askama_derive" | ||||
| version = "0.12.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" | ||||
| dependencies = [ | ||||
|  "askama_parser", | ||||
|  "basic-toml", | ||||
|  "mime", | ||||
|  "mime_guess", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "serde", | ||||
|  "syn 2.0.72", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "askama_escape" | ||||
| version = "0.10.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "askama_parser" | ||||
| version = "0.2.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" | ||||
| dependencies = [ | ||||
|  "nom", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "async-lock" | ||||
| version = "3.4.0" | ||||
|  | @ -121,13 +165,13 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "async-trait" | ||||
| version = "0.1.60" | ||||
| version = "0.1.81" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" | ||||
| checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "syn 1.0.106", | ||||
|  "syn 2.0.72", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -154,6 +198,61 @@ version = "1.1.0" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "axum" | ||||
| version = "0.7.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" | ||||
| dependencies = [ | ||||
|  "async-trait", | ||||
|  "axum-core", | ||||
|  "bytes", | ||||
|  "futures-util", | ||||
|  "http", | ||||
|  "http-body", | ||||
|  "http-body-util", | ||||
|  "hyper", | ||||
|  "hyper-util", | ||||
|  "itoa", | ||||
|  "matchit", | ||||
|  "memchr", | ||||
|  "mime", | ||||
|  "percent-encoding", | ||||
|  "pin-project-lite", | ||||
|  "rustversion", | ||||
|  "serde", | ||||
|  "serde_json", | ||||
|  "serde_path_to_error", | ||||
|  "serde_urlencoded", | ||||
|  "sync_wrapper 1.0.1", | ||||
|  "tokio", | ||||
|  "tower", | ||||
|  "tower-layer", | ||||
|  "tower-service", | ||||
|  "tracing", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "axum-core" | ||||
| version = "0.4.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" | ||||
| dependencies = [ | ||||
|  "async-trait", | ||||
|  "bytes", | ||||
|  "futures-util", | ||||
|  "http", | ||||
|  "http-body", | ||||
|  "http-body-util", | ||||
|  "mime", | ||||
|  "pin-project-lite", | ||||
|  "rustversion", | ||||
|  "sync_wrapper 0.1.2", | ||||
|  "tower-layer", | ||||
|  "tower-service", | ||||
|  "tracing", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "backtrace" | ||||
| version = "0.3.73" | ||||
|  | @ -187,6 +286,15 @@ version = "1.6.0" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "basic-toml" | ||||
| version = "0.1.9" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" | ||||
| dependencies = [ | ||||
|  "serde", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bincode" | ||||
| version = "1.3.3" | ||||
|  | @ -548,6 +656,16 @@ dependencies = [ | |||
|  "zeroize", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "deranged" | ||||
| version = "0.3.11" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" | ||||
| dependencies = [ | ||||
|  "powerfmt", | ||||
|  "serde", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "dhcproto" | ||||
| version = "0.12.0" | ||||
|  | @ -1145,12 +1263,101 @@ dependencies = [ | |||
|  "windows", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "http" | ||||
| version = "1.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" | ||||
| dependencies = [ | ||||
|  "bytes", | ||||
|  "fnv", | ||||
|  "itoa", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "http-body" | ||||
| version = "1.0.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" | ||||
| dependencies = [ | ||||
|  "bytes", | ||||
|  "http", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "http-body-util" | ||||
| version = "0.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" | ||||
| dependencies = [ | ||||
|  "bytes", | ||||
|  "futures-util", | ||||
|  "http", | ||||
|  "http-body", | ||||
|  "pin-project-lite", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "httparse" | ||||
| version = "1.9.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "httpdate" | ||||
| version = "1.0.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "humansize" | ||||
| version = "2.1.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" | ||||
| dependencies = [ | ||||
|  "libm", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "humantime" | ||||
| version = "2.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "hyper" | ||||
| version = "1.4.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" | ||||
| dependencies = [ | ||||
|  "bytes", | ||||
|  "futures-channel", | ||||
|  "futures-util", | ||||
|  "http", | ||||
|  "http-body", | ||||
|  "httparse", | ||||
|  "httpdate", | ||||
|  "itoa", | ||||
|  "pin-project-lite", | ||||
|  "smallvec", | ||||
|  "tokio", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "hyper-util" | ||||
| version = "0.1.7" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" | ||||
| dependencies = [ | ||||
|  "bytes", | ||||
|  "futures-util", | ||||
|  "http", | ||||
|  "http-body", | ||||
|  "hyper", | ||||
|  "pin-project-lite", | ||||
|  "tokio", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "iana-time-zone" | ||||
| version = "0.1.53" | ||||
|  | @ -1366,6 +1573,12 @@ version = "0.1.10" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "matchit" | ||||
| version = "0.7.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "md-5" | ||||
| version = "0.10.6" | ||||
|  | @ -1403,6 +1616,22 @@ dependencies = [ | |||
|  "quote", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "mime" | ||||
| version = "0.3.17" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "mime_guess" | ||||
| version = "2.0.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" | ||||
| dependencies = [ | ||||
|  "mime", | ||||
|  "unicase", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "minimal-lexical" | ||||
| version = "0.2.1" | ||||
|  | @ -1514,6 +1743,12 @@ dependencies = [ | |||
|  "zeroize", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "num-conv" | ||||
| version = "0.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "num-integer" | ||||
| version = "0.1.45" | ||||
|  | @ -1646,7 +1881,6 @@ dependencies = [ | |||
|  "moka", | ||||
|  "nzr-api", | ||||
|  "serde", | ||||
|  "tarpc", | ||||
|  "tokio", | ||||
|  "tracing", | ||||
|  "tracing-subscriber", | ||||
|  | @ -1661,6 +1895,20 @@ dependencies = [ | |||
|  "memchr", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "omyacid" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "anyhow", | ||||
|  "askama", | ||||
|  "axum", | ||||
|  "moka", | ||||
|  "nzr-api", | ||||
|  "tokio", | ||||
|  "tracing", | ||||
|  "tracing-subscriber", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "once_cell" | ||||
| version = "1.19.0" | ||||
|  | @ -1865,6 +2113,12 @@ version = "0.3.26" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "powerfmt" | ||||
| version = "0.2.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ppv-lite86" | ||||
| version = "0.2.17" | ||||
|  | @ -2098,6 +2352,12 @@ dependencies = [ | |||
|  "windows-sys 0.52.0", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rustversion" | ||||
| version = "1.0.17" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ryu" | ||||
| version = "1.0.12" | ||||
|  | @ -2162,6 +2422,16 @@ dependencies = [ | |||
|  "serde", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde_path_to_error" | ||||
| version = "0.1.16" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" | ||||
| dependencies = [ | ||||
|  "itoa", | ||||
|  "serde", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde_spanned" | ||||
| version = "0.6.7" | ||||
|  | @ -2285,9 +2555,9 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "smallvec" | ||||
| version = "1.10.0" | ||||
| version = "1.13.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" | ||||
| checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" | ||||
| dependencies = [ | ||||
|  "serde", | ||||
| ] | ||||
|  | @ -2591,6 +2861,18 @@ dependencies = [ | |||
|  "unicode-ident", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "sync_wrapper" | ||||
| version = "0.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "sync_wrapper" | ||||
| version = "1.0.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "syslog" | ||||
| version = "7.0.0" | ||||
|  | @ -2720,13 +3002,16 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "time" | ||||
| version = "0.3.17" | ||||
| version = "0.3.36" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" | ||||
| checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" | ||||
| dependencies = [ | ||||
|  "deranged", | ||||
|  "itoa", | ||||
|  "libc", | ||||
|  "num-conv", | ||||
|  "num_threads", | ||||
|  "powerfmt", | ||||
|  "serde", | ||||
|  "time-core", | ||||
|  "time-macros", | ||||
|  | @ -2734,16 +3019,17 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "time-core" | ||||
| version = "0.1.0" | ||||
| version = "0.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" | ||||
| checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "time-macros" | ||||
| version = "0.2.6" | ||||
| version = "0.2.18" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" | ||||
| checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" | ||||
| dependencies = [ | ||||
|  "num-conv", | ||||
|  "time-core", | ||||
| ] | ||||
| 
 | ||||
|  | @ -2877,6 +3163,34 @@ dependencies = [ | |||
|  "winnow", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "tower" | ||||
| version = "0.4.13" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" | ||||
| dependencies = [ | ||||
|  "futures-core", | ||||
|  "futures-util", | ||||
|  "pin-project", | ||||
|  "pin-project-lite", | ||||
|  "tokio", | ||||
|  "tower-layer", | ||||
|  "tower-service", | ||||
|  "tracing", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "tower-layer" | ||||
| version = "0.3.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "tower-service" | ||||
| version = "0.3.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "tracing" | ||||
| version = "0.1.40" | ||||
|  | @ -3005,6 +3319,15 @@ dependencies = [ | |||
|  "version_check", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "unicase" | ||||
| version = "2.7.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" | ||||
| dependencies = [ | ||||
|  "version_check", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "unicode-bidi" | ||||
| version = "0.3.15" | ||||
|  |  | |||
|  | @ -1,3 +1,3 @@ | |||
| [workspace] | ||||
| members = ["nzrd", "nzr-api", "client", "nzrdhcp", "nzr-virt"] | ||||
| members = ["nzrd", "nzr-api", "client", "nzrdhcp", "nzr-virt", "omyacid"] | ||||
| resolver = "2" | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ pub struct SOAConfig { | |||
| #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
| pub struct DNSConfig { | ||||
|     pub listen_addr: String, | ||||
|     pub port: u16, | ||||
|     pub default_zone: Name, | ||||
|     pub soa: SOAConfig, | ||||
| } | ||||
|  | @ -40,6 +41,15 @@ pub struct DNSConfig { | |||
| #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
| pub struct DHCPConfig { | ||||
|     pub listen_addr: String, | ||||
|     pub port: u16, | ||||
| } | ||||
| 
 | ||||
| /// Cloud-init configuration, used by omyacid.
 | ||||
| #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
| pub struct CloudConfig { | ||||
|     pub listen_addr: String, | ||||
|     pub port: u16, | ||||
|     pub admin_user: String, | ||||
| } | ||||
| 
 | ||||
| /// Server<->Client RPC configuration.
 | ||||
|  | @ -62,6 +72,7 @@ pub struct Config { | |||
|     pub storage: StorageConfig, | ||||
|     pub dns: DNSConfig, | ||||
|     pub dhcp: DHCPConfig, | ||||
|     pub cloud: CloudConfig, | ||||
| } | ||||
| 
 | ||||
| impl Default for Config { | ||||
|  | @ -84,8 +95,9 @@ impl Default for Config { | |||
|                 base_image_pool: "images".to_owned(), | ||||
|             }, | ||||
|             dns: DNSConfig { | ||||
|                 listen_addr: "127.0.0.1:5353".to_owned(), | ||||
|                 default_zone: Name::from_utf8("servers.locaddral").unwrap(), | ||||
|                 listen_addr: "127.0.0.1".to_owned(), | ||||
|                 port: 5353, | ||||
|                 default_zone: Name::from_utf8("servers.local").unwrap(), | ||||
|                 soa: SOAConfig { | ||||
|                     nzr_domain: Name::from_utf8("nzr.local").unwrap(), | ||||
|                     contact: Name::from_utf8("admin.nzr.local").unwrap(), | ||||
|  | @ -96,6 +108,12 @@ impl Default for Config { | |||
|             }, | ||||
|             dhcp: DHCPConfig { | ||||
|                 listen_addr: "127.0.0.1".to_owned(), | ||||
|                 port: 67, | ||||
|             }, | ||||
|             cloud: CloudConfig { | ||||
|                 listen_addr: "0.0.0.0".to_owned(), | ||||
|                 port: 80, | ||||
|                 admin_user: "admin".to_owned(), | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										14
									
								
								omyacid/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								omyacid/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| [package] | ||||
| name = "omyacid" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| [dependencies] | ||||
| nzr-api = { path = "../nzr-api" } | ||||
| tokio = { version = "1", features = ["rt-multi-thread", "macros"] } | ||||
| axum = "0.7" | ||||
| tracing = "0.1" | ||||
| tracing-subscriber = "0.3" | ||||
| anyhow = "1" | ||||
| askama = "0.12" | ||||
| moka = { version = "0.12.8", features = ["future"] } | ||||
							
								
								
									
										95
									
								
								omyacid/src/ctx.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								omyacid/src/ctx.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | |||
| use std::hash::RandomState; | ||||
| use std::net::Ipv4Addr; | ||||
| use std::sync::Arc; | ||||
| use std::time::Duration; | ||||
| 
 | ||||
| use anyhow::Context as _; | ||||
| use anyhow::Result; | ||||
| use moka::future::Cache; | ||||
| use nzr_api::config::Config; | ||||
| use nzr_api::model::Instance; | ||||
| use nzr_api::InstanceQuery; | ||||
| use nzr_api::NazrinClient; | ||||
| use tokio::net::UnixStream; | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| struct InstanceMeta { | ||||
|     pub inst: Instance, | ||||
|     pub userdata: Vec<u8>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct Context { | ||||
|     api_client: NazrinClient, | ||||
|     config: Arc<Config>, | ||||
|     host_cache: Cache<Ipv4Addr, InstanceMeta, RandomState>, | ||||
| } | ||||
| 
 | ||||
| impl Context { | ||||
|     pub async fn new(cfg: Config) -> Result<Self> { | ||||
|         let api_client = { | ||||
|             let sock = UnixStream::connect(&cfg.rpc.socket_path) | ||||
|                 .await | ||||
|                 .context("Connection to nzrd failed")?; | ||||
|             nzr_api::new_client(sock) | ||||
|         }; | ||||
| 
 | ||||
|         let host_cache = Cache::builder() | ||||
|             .time_to_live(Duration::from_secs(15)) | ||||
|             .max_capacity(5) | ||||
|             .build(); | ||||
| 
 | ||||
|         Ok(Self { | ||||
|             api_client, | ||||
|             host_cache, | ||||
|             config: Arc::new(cfg), | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     // Internal function to hydrate the instance metadata, if needed
 | ||||
|     async fn get_instmeta(&self, addr: Ipv4Addr) -> Result<Option<InstanceMeta>> { | ||||
|         if let Some(meta) = self.host_cache.get(&addr).await { | ||||
|             tracing::debug!("Cache hit!"); | ||||
|             Ok(Some(meta)) | ||||
|         } else { | ||||
|             let inst = self | ||||
|                 .api_client | ||||
|                 .find_instance(nzr_api::default_ctx(), InstanceQuery::Ipv4Addr(addr)) | ||||
|                 .await | ||||
|                 .context("RPC error")? | ||||
|                 .map_err(|e| anyhow::anyhow!("nzrd error: {e}"))?; | ||||
|             if let Some(inst) = inst { | ||||
|                 let userdata = self | ||||
|                     .api_client | ||||
|                     .get_instance_userdata(nzr_api::default_ctx(), inst.id) | ||||
|                     .await | ||||
|                     .context("RPC error")? | ||||
|                     .map_err(|e| anyhow::anyhow!("nzrd error: {e}"))?; | ||||
| 
 | ||||
|                 let meta = InstanceMeta { inst, userdata }; | ||||
| 
 | ||||
|                 self.host_cache.insert(addr, meta.clone()).await; | ||||
| 
 | ||||
|                 Ok(Some(meta)) | ||||
|             } else { | ||||
|                 Ok(None) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub async fn get_instance(&self, addr: Ipv4Addr) -> Result<Option<Instance>> { | ||||
|         self.get_instmeta(addr) | ||||
|             .await | ||||
|             .map(|opt| opt.map(|im| im.inst)) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn get_inst_userdata(&self, addr: Ipv4Addr) -> Result<Option<Vec<u8>>> { | ||||
|         self.get_instmeta(addr) | ||||
|             .await | ||||
|             .map(|opt| opt.map(|im| im.userdata)) | ||||
|     } | ||||
| 
 | ||||
|     pub fn cfg(&self) -> &Config { | ||||
|         &self.config | ||||
|     } | ||||
| } | ||||
							
								
								
									
										120
									
								
								omyacid/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								omyacid/src/main.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,120 @@ | |||
| mod ctx; | ||||
| mod model; | ||||
| 
 | ||||
| use std::{ | ||||
|     net::{IpAddr, SocketAddr}, | ||||
|     process::ExitCode, | ||||
|     str::FromStr, | ||||
| }; | ||||
| 
 | ||||
| use askama::Template; | ||||
| use axum::{ | ||||
|     extract::{ConnectInfo, State}, | ||||
|     http::StatusCode, | ||||
|     routing::get, | ||||
|     Router, | ||||
| }; | ||||
| use model::Metadata; | ||||
| use nzr_api::config::Config; | ||||
| 
 | ||||
| async fn get_meta_data( | ||||
|     State(ctx): State<ctx::Context>, | ||||
|     ConnectInfo(addr): ConnectInfo<SocketAddr>, | ||||
| ) -> Result<String, StatusCode> { | ||||
|     if let IpAddr::V4(ip) = addr.ip() { | ||||
|         match ctx.get_instance(ip).await { | ||||
|             Ok(Some(inst)) => { | ||||
|                 let meta = Metadata { | ||||
|                     inst_name: &inst.name, | ||||
|                     ssh_pubkeys: Vec::new(), // TODO
 | ||||
|                     username: Some(ctx.cfg().cloud.admin_user.as_ref()), | ||||
|                 }; | ||||
| 
 | ||||
|                 meta.render().map_err(|e| { | ||||
|                     tracing::error!("Renderer error: {e}"); | ||||
|                     StatusCode::INTERNAL_SERVER_ERROR | ||||
|                 }) | ||||
|             } | ||||
|             Ok(None) => { | ||||
|                 tracing::warn!("Request from unregistered server {ip}"); | ||||
|                 Err(StatusCode::FORBIDDEN) | ||||
|             } | ||||
|             Err(err) => { | ||||
|                 tracing::warn!("{err}"); | ||||
|                 Err(StatusCode::INTERNAL_SERVER_ERROR) | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         Err(StatusCode::BAD_REQUEST) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| async fn get_user_data( | ||||
|     State(ctx): State<ctx::Context>, | ||||
|     ConnectInfo(addr): ConnectInfo<SocketAddr>, | ||||
| ) -> Result<Vec<u8>, StatusCode> { | ||||
|     if let IpAddr::V4(ip) = addr.ip() { | ||||
|         match ctx.get_inst_userdata(ip).await { | ||||
|             Ok(Some(data)) => Ok(data), | ||||
|             Ok(None) => { | ||||
|                 tracing::warn!("Request from unregistered server {ip}"); | ||||
|                 Err(StatusCode::FORBIDDEN) | ||||
|             } | ||||
|             Err(err) => { | ||||
|                 tracing::warn!("{err}"); | ||||
|                 Err(StatusCode::INTERNAL_SERVER_ERROR) | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         Err(StatusCode::BAD_REQUEST) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[tokio::main] | ||||
| async fn main() -> ExitCode { | ||||
|     tracing_subscriber::fmt().init(); | ||||
|     let cfg: Config = match Config::figment().extract() { | ||||
|         Ok(cfg) => cfg, | ||||
|         Err(err) => { | ||||
|             tracing::error!("Unable to get configuration: {err}"); | ||||
|             return ExitCode::FAILURE; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let http_sock = { | ||||
|         let addr = match IpAddr::from_str(&cfg.cloud.listen_addr) { | ||||
|             Ok(addr) => addr, | ||||
|             Err(err) => { | ||||
|                 tracing::error!("Invalid listen IP address ({err})"); | ||||
|                 return ExitCode::FAILURE; | ||||
|             } | ||||
|         }; | ||||
|         match tokio::net::TcpListener::bind((addr, cfg.cloud.port)).await { | ||||
|             Ok(sock) => sock, | ||||
|             Err(err) => { | ||||
|                 tracing::error!("Failed to bind to {addr}:{}: {err}", cfg.cloud.port); | ||||
|                 return ExitCode::FAILURE; | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let ctx = match ctx::Context::new(cfg).await { | ||||
|         Ok(ctx) => ctx, | ||||
|         Err(err) => { | ||||
|             tracing::error!("{err}"); | ||||
|             return ExitCode::FAILURE; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let app = Router::new() | ||||
|         .route("/meta-data", get(get_meta_data)) | ||||
|         .route("/user-data", get(get_user_data)) | ||||
|         .with_state(ctx); | ||||
| 
 | ||||
|     if let Err(err) = axum::serve(http_sock, app).await { | ||||
|         tracing::error!("axum error: {err}"); | ||||
|         return ExitCode::FAILURE; | ||||
|     } | ||||
| 
 | ||||
|     ExitCode::SUCCESS | ||||
| } | ||||
							
								
								
									
										8
									
								
								omyacid/src/model.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								omyacid/src/model.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| use askama::Template; | ||||
| #[derive(Template)] | ||||
| #[template(path = "meta-data.yml")] | ||||
| pub struct Metadata<'a> { | ||||
|     pub inst_name: &'a str, | ||||
|     pub ssh_pubkeys: Vec<&'a String>, | ||||
|     pub username: Option<&'a str>, | ||||
| } | ||||
							
								
								
									
										11
									
								
								omyacid/templates/meta-data.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								omyacid/templates/meta-data.yml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| instance_id: "iid-{{ inst_name }}" | ||||
| local_hostname: "{{ inst_name }}" | ||||
| {% if !ssh_pubkeys.is_empty() -%} | ||||
| public_keys: | ||||
| {% for key in ssh_pubkeys -%} | ||||
| - "{{ key }}" | ||||
| {% endfor %} | ||||
| {% endif -%} | ||||
| {% if let Some(user) = username -%} | ||||
| default_username: "{{ user }}" | ||||
| {%- endif %} | ||||
		Loading…
	
		Reference in a new issue